package server.storage;

import java.util.ArrayList;
import simpleUsers.*;
import forum.*;
import forum.Thread;

public class Storage {
	private ForumsHandler forums;
	private UsersHandler users;
	private ArrayList<Viewer> viewers;

	public Storage() {
		this.forums = new ForumsHandler();
		this.users = new UsersHandler();
		this.viewers = new ArrayList<Viewer>();
	}
	
	/**
	 * This method logs user in the forum
	 * 
	 * @param username
	 *            : the user who wishes to log in
	 * @param password
	 *            : the user's password
	 * @return 0 if the log in was successful <br>
	 *         -1 if the passwords are not equal <br>
	 *         -2 if the user is not registered
	 */
	public int login(String username, String password) {
		int ans = 0;
		int index = this.users.findUser(username);
		if (index != -1) {
			if (!this.users.userLoggedIn(username, password))
				ans = -1;
		} else
			ans = -2;
		return ans;
	}

	/**
	 * This method logs user off the system
	 * 
	 * @param username
	 *            : the name of the user to log off
	 * @return 0 if the logging off was successful <br>
	 *         -1 if the logging off has failed <br>
	 *         -2 if the user is not registered
	 */
	public int logoff(String username) {
		int ans = 0;
		int index = this.users.findUser(username);
		if (index != -1) {
			if (!this.users.userLoggedOff(username))
				ans = -1;
		} else
			ans = -2;
		return ans;
	}

	/**
	 * @param userToRemove
	 *            : the user we want to remove from the list
	 * @param userWhoRemoves
	 *            : the user who wants to remove the user.
	 * @return 0 if the removing was successful <br>
	 *         -1 if the userToRemove wasn't found in the list <br>
	 *         -2 if the userWhoRemoves is not logged in <br>
	 *         -3 if the userWhoRemoves is not moderator <br>
	 *         -4 if the userWhoRemoves is not registered
	 */
	public synchronized int removeUser(String userToRemove,
			String userWhoRemoves) {
		int ans = 0;
		int index = this.users.findUser(userWhoRemoves);
		if (index != -1) {
			if (this.users.isModerator(userWhoRemoves)) {
				if (this.users.isUserLoggedin(userWhoRemoves)) {
					String nameOfRemovedUser = this.users
							.removeUser(userToRemove);
					if (nameOfRemovedUser.isEmpty())
						ans = -1;
				} else
					ans = -2;
			} else
				ans = -3;
		} else
			ans = -4;
		return ans;
	}

	/**
	 * This method adds new user after the registration of the user into the
	 * forum.
	 * 
	 * @param uName
	 *            : new user's username
	 * @param fName
	 *            : new user's first name
	 * @param lName
	 *            : new user's last name
	 * @param pw
	 *            : new user's password
	 * @param mail
	 *            : new user's e-mail
	 * @param g
	 *            : new user's gender
	 * @return 0 if the adding was successful <br>
	 *         -1 if the physical adding into the list failed <br>
	 *         -2 if user with the same username exists
	 */
	public synchronized int addUser(String uName, String fName, String lName,
			String pw, String mail, char g) {
		int ans = 0;
		int index = this.users.findUser(uName);
		if (index == -1) {
			Member newUser = new Member(uName, fName, lName, pw, mail, g);
			boolean addSuccess = this.users.addUser(newUser);
			if (!addSuccess)
				ans = -1;
		} else
			ans = -2;
		return ans;
	}

	/**
	 * This method adds friend to user's friends' list.
	 * 
	 * @param username
	 *            : the user who wants to add a friend
	 * @param friendToAdd
	 *            : the friend to add
	 * @return 0 if the adding was successful <br>
	 *         -1 if the friend already exists in friends' list<br>
	 *         -2 if the user and friend are the same person <br>
	 *         -3 if the friend is not registered <br>
	 *         -4 if the user who wants to add friend is not logged in `<br>
	 *         -5 if the user is not registered
	 */
	public synchronized int addUserFriend(String username, String friendToAdd) {
		int ans = 0;
		int index1 = this.users.findUser(username);
		if (index1 != -1) {
			if (this.users.isUserLoggedin(username)) {
				int index2 = this.users.findUser(friendToAdd);
				if (index2 != -1) {
					if (index1 != index2) {
						if (!this.users.addUserFriend(username, friendToAdd))
							ans = -1;
					} else
						ans = -2;
				} else
					ans = -3;
			} else
				ans = -4;
		} else
			ans = -5;
		return ans;
	}

	/**
	 * This method removes friend from user's friends' list.
	 * 
	 * @param username
	 *            : the user who wants to remove a friend
	 * @param friendToAdd
	 *            : the friend to add
	 * @return 0 if the removing was successful <br>
	 *         -1 if the removing has failed <br>
	 *         -2 if the user who removes is not logged in
	 */
	public synchronized int removeUserFriend(String username,
			String friendToRemove) {
		int ans = 0;
		boolean loggedIn = this.users.isUserLoggedin(username);
		if (loggedIn) {
			if (this.users.removeUserFriend(username, friendToRemove).isEmpty())
				ans = -1;
		} else
			ans = -2;
		return ans;
	}

	/**
	 * This method adds a new forum with new topic to the list of forums
	 * 
	 * @param subject
	 *            : the subject of new forum
	 * @param usernameWhoAdds
	 *            : user who add the forum with this subject
	 * @return 0 if the adding was successful. <br>
	 *         -1 if the forum is already exist. <br>
	 *         -2 if the user with given username is not logged in. <br>
	 *         -3 if the user with given username isn't moderator.<br>
	 *         -4 if the user with given username is not registered <br>
	 *         -5 if subject is null or empty
	 */
	public synchronized int addForum(String subject, String usernameWhoAdds) {
		int ans = 0;
		if (!(subject == null || subject.equals(""))) {
			int index = this.users.findUser(usernameWhoAdds);
			if (index != -1) {
				if (this.users.isModerator(usernameWhoAdds)) {
					if (this.users.isUserLoggedin(usernameWhoAdds)) {
						ans = this.forums.addForum(subject);
						if (ans == -1)
							ans = -1;
					} else
						ans = -2;
				} else
					ans = -3;
			} else
				ans = -4;
		} else
			ans = -5;
		return ans;
	}

	/**
	 * This method adds a new thread to the list of threads in the specified
	 * forum
	 * 
	 * @param forumID
	 *            : the id of forum to which we want to add the thread
	 * @param subject
	 *            : the subject of the new thread
	 * @param content
	 *            : the body of the thread
	 * @param author
	 *            : the user who publishes the new thread
	 * @return 0 if the adding was successful <br>
	 *         -1. if the adding has failed, maybe the thread with this subject
	 *         is already exist, <br>
	 *         -2 if the author is not logged in.<br>
	 *         -3 if the user is not registered<br>
	 *         -4 if subject or content is null or empty
	 */
	public synchronized int addThread(int forumID, String subject,
			String content, String author) {
		int ans = 0;
		if (!(content == null || subject == null || subject.equals("") || content
				.equals(""))) {
			int index = this.users.findUser(author);
			if (index != -1) {
				if (this.users.isUserLoggedin(author)) {
					ans = this.forums.addThread(forumID, subject, content, author);
					if (ans == -1)
						ans = -1;
				} else
					ans = -2;
			} else
				ans = -3;
		} else
			ans = -4;
		return ans;
	}

	/**
	 * This method adds a new post/reply to some thread in the specified forum
	 * 
	 * @param forumID
	 *            : the forum to which thread we add the reply
	 * @param subject
	 *            : the subject of the post
	 * @param content
	 *            : the body of the post
	 * @param author
	 *            : the user who publishes the post
	 * @return 0 if the adding was successful. <br>
	 *         -1 if the adding has failed. <br>
	 *         -2 if the author is not logged in. <br>
	 *         -3 if the author is not registered. <br>
	 *         -4 content or subject is null or empty.
	 */
	public synchronized int addPost(int forumID, int postID, String subject,
			String content, String author) {
		int ans = 0;
		if (!(subject == null || content == null || content.equals("") || subject
				.equals(""))) {
			int index = this.users.findUser(author);
			if (index != -1) {
				if (this.users.isUserLoggedin(author)) {
					ans = this.forums.addReply(forumID, postID, subject, content, author);
					if (ans == -1)
						ans = -1;
				} else
					ans = -2;
			} else
				ans = -3;
		} else
			ans = -4;
		return ans;
	}

	/**
	 * 
	 * @param username
	 * @param forumID
	 * @param postID
	 * @param content
	 * @return 0 on success <br>
	 *         -1 if user has no permeations to edit this post <br>
	 *         or forum/thread not exist <br>
	 *         or such post with new content with same subject and author is
	 *         already exist <br>
	 *         -2 user not logged in <br>
	 *         -3 user does not exist <br>
	 *         -4 content is empty or null
	 */
	public synchronized int editPost(String username, int forumID, int postID,
			String content) {
		int ans = 0;
		if (!(content == null || content.equals(""))) {
			int index = this.users.findUser(username);
			if (index != -1) {
				if (this.users.isUserLoggedin(username)) {
					if (!this.forums.editPost(username, forumID, postID,
							content))
						ans = -1;
				} else
					ans = -2;
			} else
				ans = -3;
		} else
			ans = -4;
		return ans;
	}

	/**
	 * This method removes the requested post from the requested thread and
	 * forum
	 * 
	 * @param forumID
	 *            : the ID of the forum from which to remove post
	 * @param postID
	 *            : the post to remove
	 * @return 0 if the removing is successful <br>
	 *         -1 if the user is not logged in <br>
	 *         -2 if the user does not have a suitable authority <br>
	 *         -3 if the post does not exist <br>
	 *         -5 if the forum does not exist
	 */
	public synchronized int removePost(String username, int forumID, int postID) {
		int ans = 0;
		Forum f = this.forums.getForum(forumID);
		if (f != null) {
			Post p = f.findPost(postID);
			if (p != null) {
				if (this.users.isModerator(username)
						|| p.getAuthor().equals(username)) {
					if (this.users.isUserLoggedin(username)) {
						this.forums.removePost(forumID, postID);
					} else
						ans = -1;
				} else
					ans = -2;
			} else
				ans = -3;
		} else
			ans = -5;
		return ans;
	}

	/**
	 * This method removes a requested thread from the forum with forumID.
	 * 
	 * @param username
	 *            : the user who wishes to remove the thread
	 * @param forumID
	 *            : the forum from which we want to remove the thread
	 * @param rootPostID
	 * @return 0 if the removing was successful <br>
	 *         -1 if the user is not logged in <br>
	 *         -2 if the user does not have the authority for removing or the
	 *         user is not registered. <br>
	 *         -3 if thread does not exist <br>
	 *         -4 if forum does not exist
	 */
	public synchronized int removeThread(String username, int forumID,
			int rootPostID) {
		int ans = 0;
		Forum f = this.forums.getForum(forumID);
		if (f != null) {
			Thread t = f.getThread(rootPostID);
			if (t != null) {
				if (this.users.isModerator(username)
						|| t.getRoot().getAuthor().equals(username)) {
					if (this.users.isUserLoggedin(username)) {
						this.forums.removeThread(forumID, rootPostID);
					} else
						ans = -1;
				} else
					ans = -2;
			} else
				ans = -3;
		} else
			ans = -4;
		return ans;
	}

	/**
	 * This method removes a requested forum from the list of forums.
	 * 
	 * @param username
	 *            : the user who wishes to remove the forum.
	 * @param forumID
	 *            : the forum to remove
	 * @return 0 if the removing was successful. <br>
	 *         -1 if the user is not logged in moderator. <br>
	 *         -2 if the user is not moderator or not registered user. <br>
	 *         -3 if forum does not exist.
	 */
	public synchronized int removeForum(String username, int forumID) {
		int ans = 0;
		Forum f = this.forums.getForum(forumID);
		if (f != null) {
			if (this.users.isModerator(username)) {
				if (this.users.isUserLoggedin(username)) {
					this.forums.removeForum(forumID);
				} else
					ans = -1;
			} else
				ans = -2;
		} else
			ans = -3;
		return ans;
	}

	/**
	 * @return the list of topics of all forums if the users is logged in else
	 *         return an empty string
	 */
	public synchronized String getListOfForums(String username) {
		if (this.users.isUserLoggedin(username)) {
			return this.forums.showForums();
		}
		return "";
	}

	/**
	 * @param forumID
	 *            : the forum we want to show its' threads' topics
	 * @return threads' topics of the specified forum if the user is logged in
	 *         else return an empty string
	 */
	public synchronized String getThreadsTopicsOfForum(String username,
			int forumID) {
		if (this.users.isUserLoggedin(username))
			return this.forums.getForum(forumID).showForumTopics();
		return "";
	}

	/**
	 * @param forumID
	 *            : the forum we want to show its' threads
	 * @return threads of the specified forum if the user is logged in else
	 *         returns an empty string
	 */
	public synchronized String getThreadsOfTopic(String username, int forumID,
			int rootPostID) {
		if (this.users.isUserLoggedin(username))
			return this.forums.getForum(forumID).getThread(rootPostID)
					.showAllTread();
		return "";
	}

	/**
	 * @return the forums
	 */
	public synchronized ForumsHandler getForums() {
		return forums;
	}

        /**
         * @param username: we want to get back the list of username's friends
         * @return list of usernames' friends.
         */
        public synchronized ArrayList<String> getFriendsOfUser(String username){
        	if (this.users.isUserLoggedin(username))
        		return this.users.getListOfFriends(username);
        	return null;
        }

        /**
         * This method will be useful for the returning liggedInMsg in controller!!!
         * It will be easy to check if the logged in user is moderator!!!
         * @param username: the user to check
         * @return true or false according to the answer of usersHandler
         */
        public synchronized boolean isUserModerator(String username){
            return this.users.isModerator(username);
        }
        
        /**
         * 
         * @param id of the root post
         * @return thread
         */
        public Thread getThreadByID(int id) {
        	return forums.getTread(id);
        }
        
        public Viewer findViewerByName(String uName) {
        	if(this.viewers == null) {
        		this.viewers = new ArrayList<Viewer>();
        	}
        	Viewer ans = null;
        	for (int i=0; i<viewers.size(); i++) {
        		if (viewers.get(i).getUsername().equals(uName)) {
        			ans = viewers.get(i);
        		}
        	}
        	return ans;
        }
        
        public void removeViewerByName(String uName) {
        	if(this.viewers == null) {
        		this.viewers = new ArrayList<Viewer>();
        	}
        	Viewer v = this.findViewerByName(uName);
        	if (v != null) {
        		this.viewers.remove(v);
        		v.getThread().removeViewer(uName);
        	}
        }
        
        public void addViewerByName(String uName, Thread t) {
        	if(this.viewers == null) {
        		this.viewers = new ArrayList<Viewer>();
        	}
        	removeViewerByName(uName);
        	Viewer v = new Viewer(uName, t);
        	this.viewers.add(v);
        }
        
        public Post getPostByID(int pId) {
        	Post ans = null;
        	ans = this.forums.getPost(pId);
        	return ans;
        }
        
        public Thread getParentThread(int postID) {
        	Post parentPost = this.getPostByID(postID);
        	while(parentPost.getParent() != null) {
        		parentPost = parentPost.getParent();
        	}
        	return this.getForums().getTread(parentPost.getID());
        }
        
	// ////////////////////////TO DELETE AFTER
	// TEST!!!!!!!!!!!!!!!!/////////////////////
	public ArrayList<Member> getUsers() {
		return this.users.getTotalUsers();
	}

}
